#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#include <libgen.h>

#pragma pack(push, 1)

typedef struct
{
    char name[100];      // 文件名
    uint64_t size;       // 文件大小
} file_info;

#pragma pack(pop)

// 创建目录（如果不存在）
int create_directory(const char* path) {
    char* path_copy = strdup(path);
    char* dir = dirname(path_copy);
    
    struct stat st;
    if (stat(dir, &st) == -1) {
        // 目录不存在，尝试创建
        if (mkdir(dir, 0755) == -1) {
            free(path_copy);
            return -1;
        }
    }
    
    free(path_copy);
    return 0;
}

int main(int argc, char** argv)
{
    if(argc != 3)
    {
        fprintf(stderr, "Usage: %s <server_ip> <server_port>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    const char* server_ip = argv[1];
    int server_port = atoi(argv[2]);

    // 忽略 SIGPIPE 信号
    signal(SIGPIPE, SIG_IGN);

    // 第1步：创建套接字
    int sock_client = socket(AF_INET, SOCK_STREAM, 0);
    if(sock_client == -1)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 第2步：连接服务器
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(server_port);
    server_addr.sin_addr.s_addr = inet_addr(server_ip);

    if(connect(sock_client, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1)
    {
        perror("connect");
        close(sock_client);
        exit(EXIT_FAILURE);
    }

    printf("成功连接到服务器 %s:%d\n", server_ip, server_port);
    printf("开始接收文件...\n\n");

    int file_count = 0;
    uint64_t total_received = 0;

    // 循环接收文件
    while(1)
    {
        file_info fi;
        ssize_t bytes_received;
        
        // 接收文件信息
        bytes_received = recv(sock_client, &fi, sizeof(fi), 0);
        
        if(bytes_received == 0)
        {
            // 服务器正常关闭连接
            printf("文件传输完成！\n");
            break;
        }
        else if(bytes_received == -1)
        {
            if(errno == EAGAIN || errno == EWOULDBLOCK)
            {
                // 超时，可能传输已完成
                printf("接收超时，文件传输可能已完成\n");
                break;
            }
            else
            {
                perror("recv file_info");
                break;
            }
        }
        else if(bytes_received != sizeof(fi))
        {
            fprintf(stderr, "接收文件信息不完整: %zd/%zu bytes\n", bytes_received, sizeof(fi));
            break;
        }

        file_count++;
        printf("正在接收第 %d 个文件: %s (大小: %lu bytes)\n", file_count, fi.name, fi.size);

        // 创建必要的目录结构
        if(create_directory(fi.name) == -1)
        {
            fprintf(stderr, "创建目录失败: %s\n", fi.name);
            continue; // 跳过这个文件，继续下一个
        }

        // 创建文件
        int fd = open(fi.name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if(fd == -1)
        {
            perror("open file");
            continue; // 跳过这个文件，继续下一个
        }

        // 接收文件数据
        char buffer[4096];
        uint64_t remaining = fi.size;
        uint64_t file_received = 0;
        int ret;
        
        while(remaining > 0)
        {
            size_t to_read = sizeof(buffer);
            if(remaining < to_read)
                to_read = remaining;
            
            ret = recv(sock_client, buffer, to_read, 0);
            
            if(ret == -1)
            {
                if(errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    printf("接收超时，文件 %s 可能不完整\n", fi.name);
                    break;
                }
                else
                {
                    perror("recv file data");
                    break;
                }
            }
            else if(ret == 0)
            {
                printf("服务器断开连接\n");
                break;
            }
            
            // 写入文件
            ssize_t bytes_written = write(fd, buffer, ret);
            if(bytes_written != ret)
            {
                perror("write file");
                break;
            }
            
            file_received += ret;
            remaining -= ret;
            
            // 显示进度
            if(fi.size > 0)
            {
                int progress = (int)((double)file_received / fi.size * 100);
                printf("\r进度: %d%% (%lu/%lu bytes)", progress, file_received, fi.size);
                fflush(stdout);
            }
        }
        
        printf("\n");
        
        if(file_received == fi.size)
        {
            printf("文件接收成功: %s\n", fi.name);
            total_received += file_received;
        }
        else
        {
            fprintf(stderr, "文件接收不完整: %s (%lu/%lu bytes)\n", 
                    fi.name, file_received, fi.size);
            // 删除不完整的文件
            unlink(fi.name);
        }
        
        close(fd);
    }

    printf("\n文件传输统计:\n");
    printf("成功接收文件数量: %d\n", file_count);
    printf("总接收数据量: %lu bytes\n", total_received);

    // 关闭套接字
    close(sock_client);

    return 0;
}
